﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TByte.XnaHelper;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TByte.XnaHelper.Input;
using System.IO;

namespace TByte.XnaHelper.GameObjects.DontUse
{
    public class MenuGameState : GameState
    {
        #region Fields
        SpriteGameObject background;
        Dictionary<string, GameObject> menus = new Dictionary<string, GameObject>();
        string currentMenu = string.Empty;
        GameObject menuWrapper = new GameObject("Wrapper");
        #endregion

        #region Methods
        void AlignMenu()
        {
            if (background != null)
            {
                background.Scale = Math.Max(Manager.Screen.X / (background.Width / background.Scale), Manager.Screen.Y / (background.Height / background.Scale));
                background.RelativePosition = Manager.Screen / 2;
            }
        }
        void SetMenu(string menu)
        {
            //Set menu
            if (menus.ContainsKey(menu))
            {
                //Remove current menu
                if (menus.ContainsKey(currentMenu))
                    menuWrapper.RemoveChild(menus[currentMenu]);

                //Add new menu
                menuWrapper.AddChild(menus[menu]);

                currentMenu = menu;
            }
        }
        void AddMenu(GameObject menu)
        {
            menus[menu.Name] = menu;
        }
        void BuildMenus(Vector2 menuPosition, Color fontColor, Action quitAction,Action playAction, int buttonOffset = 10)
        {
            menus = new Dictionary<string, GameObject>();

            SpriteSheet buttonSheet = null;
            SpriteFont menuFont = null;

            try
            {
                buttonSheet = Assets.SpriteSheet("menuButton");
            }
            catch (IOException)
            {
                GameConsole.ErrorLog("No button sheet was found. Loading default buttons...");
            }

            try
            {
                menuFont = Assets.Font("menuFont");
            }
            catch (IOException)
            {
                GameConsole.ErrorLog("No menuFont was found. Using Console Font...");
                menuFont = Assets.Font("consoleFont");
            }

            #region CreateMenus
            {
                GameObject mainMenu = new GameObject("Main");
                mainMenu.RelativePosition = menuPosition;
                AddMenu(mainMenu);

                GameObject optionsMenu = new GameObject("Settings");
                optionsMenu.RelativePosition = menuPosition;
                AddMenu(optionsMenu);

                GameObject displayMenu = new GameObject("Display");
                displayMenu.RelativePosition = menuPosition;
                AddMenu(displayMenu);

                GameObject controlsMenu = new GameObject("Controls");
                controlsMenu.RelativePosition = menuPosition;
                AddMenu(controlsMenu);
            }
            #endregion

            #region Main
            {
                ButtonGameObject play = new ButtonGameObject(buttonSheet, "Play", fontColor, menuFont, "playButton");
                play.RelativePosition = new Vector2(0, 0);
                play.OnClick += playAction;
                menus["Main"].AddChild(play);

                ButtonGameObject settings = new ButtonGameObject(buttonSheet, "Settings", fontColor, menuFont, "settingsButton");
                settings.RelativePosition = new Vector2(0, (settings.Height + buttonOffset));
                settings.OnClick += () => SetMenu("Settings");
                menus["Main"].AddChild(settings);

                ButtonGameObject quit = new ButtonGameObject(buttonSheet, "Quit", fontColor, menuFont, "quitButton");
                quit.RelativePosition = new Vector2(0, (quit.Height + buttonOffset) * 2);
                quit.OnClick += quitAction;
                menus["Main"].AddChild(quit);
            }
            #endregion

            #region Settings
            {
                ButtonGameObject controls = new ButtonGameObject(buttonSheet, "Key Bindings", fontColor, menuFont, "controlsButton");
                controls.RelativePosition = new Vector2(0, 0);
                controls.OnClick += () => SetMenu("Controls");
                menus["Settings"].AddChild(controls);

                ButtonGameObject display = new ButtonGameObject(buttonSheet, "Display", fontColor, menuFont, "displayButton");
                display.RelativePosition = new Vector2(0, (display.Height + buttonOffset));
                display.OnClick += () => SetMenu("Display");
                menus["Settings"].AddChild(display);

                ButtonGameObject back = new ButtonGameObject(buttonSheet, "Back", fontColor, menuFont, "backButton");
                back.RelativePosition = new Vector2(0, (back.Height + buttonOffset) * 2);
                back.OnClick += () => SetMenu("Main");
                menus["Settings"].AddChild(back);
            }
            #endregion

            #region Display
            {
                ToggleButtonGameObject fullscreen = new ToggleButtonGameObject(buttonSheet, new List<dynamic> { false, true }, new List<string> { "Windowed", "Fullscreen" }, 0, menuFont, fontColor, "fullscreenToggle");
                fullscreen.CurrentValue = Manager.SettingInt("isFullScreen");
                menus["Display"].AddChild(fullscreen);

                //Resolution toggle
                ToggleButtonGameObject resolutionToggle = new ToggleButtonGameObject(buttonSheet, new List<dynamic>(), new List<string>(), 0, menuFont, fontColor, "resolutionToggle");
                //Get possible resolutions
                foreach (DisplayMode mode in Manager.GraphicsDevice.Adapter.SupportedDisplayModes)
                {
                    resolutionToggle.ValueList.Add(new Tuple<int, int>(mode.Width, mode.Height));
                    resolutionToggle.ValueNames.Add(mode.Width + "x" + mode.Height);

                    if (mode.Width == Manager.SettingInt("screen_width") && mode.Height == Manager.SettingInt("screen_height"))
                    {
                        //This is the current resolution
                        resolutionToggle.CurrentValue = resolutionToggle.ValueList.Count() - 1;
                    }
                }
                resolutionToggle.RelativePosition = new Vector2(0, (resolutionToggle.Height + buttonOffset));

                menus["Display"].AddChild(resolutionToggle);

                //Save button
                ButtonGameObject saveButton = new ButtonGameObject(buttonSheet, "Save", fontColor, menuFont, "saveButton");
                saveButton.RelativePosition.Y = (saveButton.Height + buttonOffset) * 2;
                saveButton.OnClick += delegate()
                {
                    //Set resolution
                    Tuple<int, int> resolution = resolutionToggle.Value as Tuple<int, int>;
                    Manager.SettingInt("screen_width", resolution.Item1, true);
                    Manager.SettingInt("screen_height", resolution.Item2, true);

                    //Set view mode
                    Manager.SettingInt("screen_isFullScreen", (fullscreen.Value as Nullable<Boolean>).Value ? 1 : 0, true);

                    Manager.ApplyChanges();
                    Manager.SaveSettings();

                    SetMenu("Settings");
                    AlignMenu();
                };
                menus["Display"].AddChild(saveButton);

                ButtonGameObject back = new ButtonGameObject(buttonSheet, "Back", fontColor, menuFont, "backButton");
                back.RelativePosition = new Vector2(0, (back.Height + buttonOffset) * 3);
                back.OnClick += () => SetMenu("Settings");
                menus["Display"].AddChild(back);

            }
            #endregion

            #region Controls
            {
                //Process all controls
                foreach (KeyValuePair<string, string> pair in Manager.Controls)
                {
                    //get Category and name of control
                    string[] parts = pair.Key.Split('_');
                    string category = "General";
                    string controlName = string.Empty;
                    if (parts.Count() > 1)
                    {
                        category = parts[0];
                        controlName = parts[1];
                    }
                    else
                    {
                        controlName = parts[0];
                    }

                    //create menu if not existant and add button to main controls page
                    if (!menus.ContainsKey(category + "Controls"))
                    {
                        GameObject controlMenu = new GameObject(category + "Controls");
                        controlMenu.RelativePosition = menuPosition;
                        AddMenu(controlMenu);

                        //Add button to main controls menu
                        ButtonGameObject toControlMenu = new ButtonGameObject(buttonSheet, category, fontColor, menuFont, category + "ControlsButton");
                        toControlMenu.RelativePosition = new Vector2(0, (toControlMenu.Height + buttonOffset) * menus["Controls"].Children.Count());
                        toControlMenu.OnClick += () => SetMenu(category + "Controls");
                        menus["Controls"].AddChild(toControlMenu);
                    }

                    //Add control button to menu
                    ButtonGameObject button = new ButtonGameObject(buttonSheet, controlName, fontColor, menuFont, controlName + "Button");
                    button.RelativePosition = new Vector2(0, (button.Height + buttonOffset) * menus[category + "Controls"].Children.Count());
                    button.OnClick += () =>
                    {
                        InputSystem.MouseEnabled = false;
                        KeyEventHandler handler = null;
                        handler = (object sender, KeyEventArgs e) =>
                            {
                                //Enable the mouse
                                InputSystem.MouseEnabled = true;
                                //Remove this handler
                                InputSystem.KeyDown -= handler;
                                //Set binding
                                Manager.SettingInt(Manager.Controls[pair.Key], (int)e.KeyCode, true);
                            };
                        InputSystem.KeyDown += handler;
                    };
                    menus[category + "Controls"].AddChild(button);
                }

                //Add back button to new controls menu
                ButtonGameObject backbutton = new ButtonGameObject(buttonSheet, "Back", fontColor, menuFont, "backButton");
                backbutton.RelativePosition = new Vector2(0, (backbutton.Height + buttonOffset) * menus["Controls"].Children.Count());
                backbutton.OnClick += () => SetMenu("Settings");
                menus["Controls"].AddChild(backbutton);

                //Add back button to all controls submenus
                List<string> taggedMenus = new List<string>();
                foreach (KeyValuePair<string, string> pair in Manager.Controls)
                {
                    string[] parts = pair.Key.Split('_');
                    string category = "General";
                    string controlName = string.Empty;
                    if (parts.Count() > 1)
                    {
                        category = parts[0];
                    }

                    if (!taggedMenus.Contains(category))
                    {
                        ButtonGameObject back = new ButtonGameObject(buttonSheet, "Back", fontColor, menuFont, "backButton");
                        back.RelativePosition = new Vector2(0, (back.Height + buttonOffset) * menus[category + "Controls"].Children.Count());
                        back.OnClick += () => SetMenu("Controls");
                        menus[category + "Controls"].AddChild(back);

                        taggedMenus.Add(category);
                    }
                }
            }
            #endregion
        }
        #endregion

        #region Constructors
        public MenuGameState(string name, GameObject root, Action quit, Action play)
            : base(name, root)
        {
            root.Name = name;
            try
            {
                background = new SpriteGameObject(Assets.Texture("menuBG"), Vector2.Zero, Color.White, 1, "MenuBG");
            }
            catch (IOException)
            {
                GameConsole.ErrorLog("Failed to load menuBG. File does not exist.");
            }
            if(background != null)
                root.AddChild(background);
            root.AddChild(menuWrapper);
            AlignMenu();

            BuildMenus(new Vector2(50, 50), Color.White, quit,play, 10);

            SetMenu("Main");
        }
        #endregion

        #region Properties
        #endregion
    }
}
